package com.chinastock.serializer;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.reactivestreams.Publisher;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.Encoder;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author zhangfan.it
 * @date 2021/2/4
 */
public class JsonEncoder implements Encoder<Object> {
    private static final String HIBERNATE_LAZY_INITIALIZER = "hibernateLazyInitializer";

    @Override
    public boolean canEncode(ResolvableType elementType, MimeType mimeType) {
        return !Optional.ofNullable(mimeType).isPresent() || mimeType.equals(MimeTypeUtils.APPLICATION_JSON);
    }

    @Override
    public Flux<DataBuffer> encode(Publisher<?> inputStream, DataBufferFactory bufferFactory, ResolvableType elementType,
                                   MimeType mimeType, Map<String, Object> hints) {
        if (inputStream instanceof Mono) {
            return Mono.from(inputStream).map(value -> encodeValue(value, bufferFactory)).flux();
        }
        else if(inputStream instanceof Flux){
            return Flux.from(inputStream).map(value -> encodeValue(value, bufferFactory));
        }
        return null;
    }

    @Override
    public List<MimeType> getEncodableMimeTypes() {
        return Collections.singletonList(MimeTypeUtils.APPLICATION_JSON);
    }

    @Override
    public DataBuffer encodeValue(Object value, DataBufferFactory bufferFactory, ResolvableType valueType,
                                  MimeType mimeType, Map<String, Object> hints) {
        return encodeValue(value, bufferFactory);
    }

    private DataBuffer encodeValue(Object value, DataBufferFactory bufferFactory) {
        PropertyFilter profilter = (object, name, value1) -> {
            //注意这里
            //false表示last字段将被排除在外
            return !HIBERNATE_LAZY_INITIALIZER.equalsIgnoreCase(name);
        };
        DataBuffer buffer = bufferFactory.allocateBuffer();
        boolean release = true;
        try {
            byte[] bytes = JSON.toJSONBytes(value, profilter, SerializerFeature.WriteMapNullValue,
                    SerializerFeature.DisableCircularReferenceDetect);
            buffer.write(bytes);
            release = false;
        } finally {
            if (release) {
                DataBufferUtils.release(buffer);
            }
        }
        return buffer;
    }
}
